<?php
/**
 * crcl/base
 *
 * Copyright 2013 CRCL - André Sabosch - info@crcl.de
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

namespace crcl\base\structure;

interface IRelation
{
  //set base item
  public function setItem(IItem $oItem);

  public function add1to1FromCommon($sItem);
  public function add1to1FromConfig($sIni);
}

class Relation implements IRelation, \Iterator
{
  const RELATION_1to1 = '1to1';

  public function setItem(IItem $oItem)
  {
    $this->oItem = $oItem;
  }

  public function add1to1FromCommon($sItem)
  {
    $oItem = Item::createFromCommon($sItem);
    $this->createRelationItem($oItem);
  }

  public function add1to1FromConfig($sIni)
  {
    $oItem = Item::createFromConfig($sIni);
    $this->createRelationItem($oItem);
  }

  public function addNtoMFromConfig($sIniCollection, $sIniRelation)
  {
    $oCollection = Collection::createFromConfig($sIniCollection);
    $oCollectionRelation = Collection::createFromConfig($sIniRelation);

    $this->createRelationCollection($oCollection, $oCollectionRelation);
  }

  public function addNtoMFromCommon($sItem, $sItemRelation)
  {
    $oCollection = Collection::createFromCommon($sItem);
    $oCollectionRelation = Collection::createFromCommon($sItemRelation);

    $this->createRelationCollection($oCollection, $oCollectionRelation);
  }

  public function __get($name)
  {
    if (isset($this->aRelations[$name]))
    {
      return $this->aRelations[$name];
    }
    else
    {
      throw new Exception('Invalid relation.',
        Exception::ERROR_RELATION_INVALID,
        array('name' => $name));
    }
  }

  public function rewind()
  {
    return reset($this->aRelations);
  }

  public function current()
  {
    $oItem = current($this->aRelations);
    return $oItem;
  }

  public function key()
  {
    return key($this->aRelations);
  }

  public function next()
  {
    return next($this->aRelations);
  }

  public function valid()
  {
    return key($this->aRelations) !== \NULL;
  }

  /** PRIVATE *************************************************************************************/

  private $oItem = array();
  private $aRelations = array();

  private function createRelationItem(IItem $oItem)
  {
    $sName = $oItem->getName();
    if (!$this->oItem->hasField($sName))
    {
      throw new Exception('Missing foreign key.',
        Exception::ERROR_RELATION_MISSINGFOREIGNKEY,
        array('key' => $sName));
    }
    $iForeignKey = $this->oItem->$sName->get();
    $oItem->id->set($iForeignKey);
    $this->aRelations[$sName] = $oItem;
  }

  private function createRelationCollection(ICollection $oCollection, ICollection $oCollectionRelation)
  {
    $sName = $oCollection->getCollectionName();

    //TODO testen ob in beiden collections die nötigen felder vorhanden sind

    $sTableJoin = $oCollectionRelation->getTable();
    $sFieldLeft =  'id';
    $sFieldRight = $oCollection->getName();
    $sWhereField = $sTableJoin . '.' . $this->oItem->getName();
    $sWhereValue = $this->oItem->id->get();

    $oCollection->addJoinData($sTableJoin, $sFieldLeft, $sFieldRight, $sWhereField, $sWhereValue);
    $this->aRelations[$sName] = $oCollection;
  }
}